Skip to content

fix(ai): make _context.session_id the single source of truth for the chat conversation id#1272

Merged
ocervell merged 2 commits into
ai-resiliencyfrom
fix/ai-session-id-stamp
Jul 4, 2026
Merged

fix(ai): make _context.session_id the single source of truth for the chat conversation id#1272
ocervell merged 2 commits into
ai-resiliencyfrom
fix/ai-session-id-stamp

Conversation

@ocervell

@ocervell ocervell commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Two commits, one theme: _context.session_id becomes the single source of truth for the remote AI chat conversation id.

1. fix(ai): stamp session_id on runner context so remote transcript restores

The remote (web) AI channel is headless — a respawned ai task rebuilds the conversation from its _type:"ai" Mongo docs, and restore_history_from_db + the RemoteBackend poll both scope by _context.session_id. Tool-action docs get that key via _get_result_context, but the prompt/response turns only inherit _context from self.context (Runner._process_item copies it). self.session_id was resolved into a local var but never written back to self.context, so a locally-derived id left the transcript turns unqueryable → resume restored an empty history. It only worked on the platform because the dispatcher supplies session_id in the context.

Fix: write the resolved session_id back onto self.context in _init_options — one line, stamps every persisted item uniformly, idempotent on the platform. Also fixes two pre-existing stale tests (asserted the old top-level query shape) and adds TestSessionIdStampedOnContext.

2. refactor(ai): retire top-level Ai.session_id field

With #1 guaranteeing _context.session_id on every doc, the top-level Ai.session_id field is redundant — it was write-only in core and duplicated the id that restore_history_from_db, the poll, _expire_stale_pending, poll_steers, and secator-api all already key on via _context.session_id. Removes the field + its 3 constructor writes (resume prompt, turn_completed, remote pending prompt). ActionContext.session_id and the build_pending_prompt/ask_user params (the working id) are unchanged.

Cross-repo (lockstep)

  • secator-api feat/ai-chat (PR feat(hooks) - add runtime hooks #199) — updated so answer_ai_prompt resolves the pending prompt by _context.session_id (was top-level) and the steer doc stops writing a redundant top-level session_id. Must merge no later than this.
  • secator-ui feat/ai-chat — no change; getChatTranscript already queries _context.session_id.

Verification

  • Full AI unit suite: no new failures vs branch baseline (the ~68 remaining are the shfmt/safecmd-parser env failures common to all branches).
  • Empirically re-ran a remote turn: prompt/response/follow_up docs all carry _context.session_id and zero top-level session_id; answering via _context.session_id (the way updated secator-api does) is picked up by the poll and continues the turn.

Part of the AI-task reliability series → ai-resiliency (#1241).

🤖 Generated with Claude Code

…ores

The remote (web) AI channel rebuilds a conversation from its `_type:"ai"`
Mongo docs, and restore_history_from_db + the RemoteBackend poll both scope
by `_context.session_id`. Tool-action docs (shell/task/follow_up) get that key
via `_get_result_context`, but the `prompt`/`response` turns are yielded
directly and only inherit `_context` from `self.context` (Runner._process_item
copies `self.context` onto every item). `self.session_id` was resolved into a
local var but never written back to `self.context`, so when it falls back to a
locally-derived value (session_name / str(self.id)) the transcript turns land
in Mongo WITHOUT `_context.session_id` — unqueryable, so a resume restores an
empty history. On the platform this happened to work only because the
dispatcher supplies session_id in the context.

Fix the root cause: write the resolved `session_id` back onto `self.context`
in `_init_options`, making it the single source of truth. Every persisted item
(including prompt/response) is then stamped uniformly; idempotent on the
platform where the value already matches.

Also fix two stale tests that asserted the pre-`_context` query shape
(top-level `session_id`) — they were failing on the branch — and add
TestSessionIdStampedOnContext covering the local-fallback, platform-supplied,
and restore-query-key cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NNjPggRSVZ2xnLb7ZxWP5H
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e9b0dab1-9e91-4310-9ab1-9dfdb2c5a3bb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ai-session-id-stamp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ntext.session_id

Now that session_id is written onto the runner context (previous commit) and
therefore auto-stamped into `_context.session_id` on every persisted `_type:"ai"`
doc, the top-level `Ai.session_id` field is redundant. It was write-only in core
(nothing read it) and duplicated the conversation id that restore_history_from_db,
the RemoteBackend poll, `_expire_stale_pending`, and secator-api all already key
on via `_context.session_id`.

Remove the field from the Ai output type and drop the three constructor writes
(resume prompt, turn_completed marker, remote pending prompt). The conversation
id is now carried in exactly one place. ActionContext.session_id and the
build_pending_prompt/ask_user params are the working id and are unchanged.

Cross-repo: secator-api's answer_ai_prompt + steer_doc are updated in lockstep
(feat/ai-chat) to query/stamp `_context.session_id` instead of the top-level
field; the UI already correlates on `_context.session_id`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NNjPggRSVZ2xnLb7ZxWP5H
@ocervell ocervell changed the title fix(ai): stamp session_id on runner context so remote transcript restores fix(ai): make _context.session_id the single source of truth for the chat conversation id Jul 4, 2026
@ocervell ocervell merged commit cf7e549 into ai-resiliency Jul 4, 2026
3 checks passed
@ocervell ocervell deleted the fix/ai-session-id-stamp branch July 4, 2026 18:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant